"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const webSocketTool_1 = __importDefault(require("../../src/com/webSocketTool/webSocketTool"));
const FSTool_1 = __importDefault(require("../../src/lib/FSTool"));
const path_1 = __importDefault(require("path"));
const stringMd5_1 = __importDefault(require("../../src/lib/FSTool/stringMd5"));
const configTool_1 = __importDefault(require("../../src/com/configTool"));
const DBTool_1 = __importDefault(require("./DBTool/DBTool"));
const TileSet_1 = __importDefault(require("../lib/TileTool/TileSet"));
const DBConnectTool_1 = __importDefault(require("./DBTool/DBConnectTool"));
const colors_console_1 = __importDefault(require("colors-console"));
const chunkedParseJson_1 = __importDefault(require("../utils/chunkedParseJson"));
const watch = require('node-watch');
const MapResource = {
    currentDirFileCount: 0,
    currentDirFileMetadata: {
        tile2D: new Map(),
        tile3D: new Set(),
        terrain: new Set()
    },
    mapResourcesCache: null,
    dbDataIndexList: new Map(),
    openWatcher: false,
    async getMapResources(readFromCache = true) {
        await configTool_1.default.init();
        if (readFromCache && this.mapResourcesCache) {
            await this.onWatcher();
            return this.mapResourcesCache;
        }
        const data = new Date().getTime();
        const dataIndex = this.readFileFromDisk();
        const dataIndexes = await this.readFileFromDB();
        const sum = this.sumDataIndexes([dataIndex, dataIndexes]);
        const mapResources = this.format(sum);
        this.mapResourcesCache = mapResources;
        const passTime = new Date().getTime() - data;
        console.log((0, colors_console_1.default)('green', `检索资源库地图资源，搜索用时：${passTime} 毫秒，共搜索到：${mapResources.length}个地图资源`));
        return mapResources;
    },
    async onWatcher() {
        if (this.openWatcher === false && configTool_1.default.wwwPath) {
            console.log((0, colors_console_1.default)('blue', '已开启【MapResources】地理资源文件夹监听'));
            this.openWatcher = true;
            await this.getMapResources();
            let timeout;
            watch(path_1.default.join(configTool_1.default.wwwPath, '/MapResources'), { recursive: true }, (active, filePath) => {
                clearTimeout(timeout);
                const oldMapDataLength = this.mapResourcesCache.length;
                timeout = setTimeout(async () => {
                    let mapResources = await this.getMapResources();
                    const newMapDataLength = mapResources.length;
                    if (oldMapDataLength !== newMapDataLength) {
                        this.sendMapResourcesToWS(mapResources);
                    }
                }, 500);
            });
        }
    },
    decodePathList(pathList) {
        const dataPathIndex = {
            tile2D: new Map(),
            tile3D: new Set(),
            terrain: new Set()
        };
        const tile2DRegex = /\\([0-9]+)\\([0-9]+)\\([0-9]+)\.(png|jpg|jpeg|webp)$/;
        for (let i = 0; i < pathList.length; i++) {
            const dataPath = pathList[i];
            if (tile2DRegex.test(dataPath)) {
                const convertedPath = dataPath.replace(tile2DRegex, '\\{z}\\{x}\\{y}.$4').replace(/\\/g, '/');
                if (dataPathIndex.tile2D.has(convertedPath)) {
                    const tileSet = dataPathIndex.tile2D.get(convertedPath);
                    const match = dataPath.match(tile2DRegex);
                    if (match) {
                        const [z, x, y] = match.slice(1).map(Number);
                        tileSet.add(x, y, z);
                    }
                }
                else {
                    dataPathIndex.tile2D.set(convertedPath, new TileSet_1.default());
                }
            }
            else if (dataPath.endsWith('tileset.json')) {
                const tile3DPath = path_1.default.join(dataPath).replace(/\\/g, '/');
                dataPathIndex.tile3D.add(tile3DPath);
            }
            else if (dataPath.endsWith('layer.json')) {
                const terrainPath = dataPath.replace(/\\/g, '/');
                dataPathIndex.terrain.add(terrainPath);
            }
        }
        for (const [convertedPath, tileSet] of dataPathIndex.tile2D) {
            const layerProperties = tileSet.getLayerProperties();
            dataPathIndex.tile2D.set(convertedPath, layerProperties);
        }
        return dataPathIndex;
    },
    readFileFromDisk() {
        const basePath = path_1.default.join(configTool_1.default.wwwPath, '/MapResources');
        const fileList = FSTool_1.default.getFilePathList(basePath)
            .map((item) => item.replace(configTool_1.default.wwwPath, ''))
            .filter((item) => !item.includes('Exclude'));
        const fileCount = fileList.length;
        if (fileCount !== this.currentDirFileCount) {
            this.currentDirFileMetadata = this.decodePathList(fileList);
            this.currentDirFileCount = fileCount;
        }
        return this.currentDirFileMetadata;
    },
    async readFileFromDB() {
        let dbList = await DBTool_1.default.getDBInfoList();
        dbList = dbList.filter(item => !item.filePath.includes('Exclude'));
        const listMd5 = (0, stringMd5_1.default)(JSON.stringify(dbList.map((item) => {
            return { id: item.id };
        })));
        if (this.dbDataIndexList.has(listMd5)) {
            return this.dbDataIndexList.get(listMd5);
        }
        const dataIndexList = [];
        for (let i = 0; i < dbList.length; i++) {
            const dbItem = dbList[i];
            const dbName = dbItem.fileName;
            let metaData = dbItem.mataData;
            let dataIndex = null;
            if (metaData.dataIndex) {
                dataIndex = metaData.dataIndex;
                if (typeof dataIndex === 'string') {
                    try {
                        dataIndex = await (0, chunkedParseJson_1.default)(dataIndex);
                    }
                    catch (e) {
                        console.log((0, colors_console_1.default)('red', `MapResource-数据索引错误！！请检查数据索引文件长度是否正常！！`));
                        dataIndex = null;
                    }
                }
            }
            if (!dataIndex) {
                const connect = await DBConnectTool_1.default.openDB(dbName);
                const allFilePath = await connect.getAllFilePathList();
                dataIndex = MapResource.decodePathList(allFilePath.map((item) => {
                    return path_1.default.join('/DBService/' + dbName + item);
                }));
                dbItem.mataData.dataIndex = {
                    tile2D: Array.from(dataIndex.tile2D.entries()),
                    tile3D: Array.from(dataIndex.tile3D),
                    terrain: Array.from(dataIndex.terrain)
                };
                const res = await connect.setMataDataMapResources(dbItem.mataData.dataIndex);
                console.log((0, colors_console_1.default)('blue', `MapResource- ${dbName} 数据索引为空，重建数据索引成功！` + res));
            }
            dataIndex && dataIndexList.push(dataIndex);
        }
        const sum = this.sumDataIndexes(dataIndexList);
        this.dbDataIndexList.set(listMd5, sum);
        return sum;
    },
    sumDataIndexes(dataIndexList) {
        const sum = {
            tile2D: new Map(),
            tile3D: new Set(),
            terrain: new Set()
        };
        for (let i = 0; i < dataIndexList.length; i++) {
            const dataIndex = dataIndexList[i];
            for (const [convertedPath, tileSet] of dataIndex.tile2D) {
                sum.tile2D.set(convertedPath, tileSet);
            }
            for (const tile3DPath of dataIndex.tile3D) {
                sum.tile3D.add(tile3DPath);
            }
            for (const terrainPath of dataIndex.terrain) {
                sum.terrain.add(terrainPath);
            }
        }
        return sum;
    },
    sendMapResourcesToWS(mapResources) {
        const mapResourcesMsg = JSON.stringify({
            bid: 'MapResourceList',
            data: mapResources,
            timestamp: new Date().getTime()
        }, null, 4);
        console.log((0, colors_console_1.default)('magenta', '地图资源有更新，发送 WebSocket 同步信息到所有用户'));
        webSocketTool_1.default.sendToAllUser(mapResourcesMsg);
    },
    format(dataIndex) {
        const list = [];
        const ip = configTool_1.default.baseConfig.proxyAfterProxy_IPAddress;
        const webPort = configTool_1.default.baseConfig.proxyAfterProxy_Port;
        const proxyProtocol = configTool_1.default.baseConfig.proxyProtocol;
        for (const dataPath of dataIndex.terrain) {
            list.push({
                pid: (0, stringMd5_1.default)(dataPath),
                name: decodeURI(dataPath?.split('/')?.at(-2) || ''),
                catalog: '地形图层',
                dataType: 'terrain',
                showInTree: true,
                showInBox: true,
                defaultLoad: false,
                show: false,
                properties: {
                    scheme: 'CesiumTerrainProvider',
                    url: `${proxyProtocol}://${ip}:${webPort}` + dataPath.replace('/layer.json', '')
                }
            });
        }
        console.time('FindRoot');
        const tile3DSet = dataIndex.tile3D;
        const dirs = new Set();
        for (const item of tile3DSet) {
            dirs.add(path_1.default.dirname(item));
        }
        const tile3DArr = [];
        for (const item of tile3DSet) {
            let parent = path_1.default.dirname(item);
            let isRoot = true;
            while (parent !== '.' && parent !== '/') {
                parent = path_1.default.dirname(parent);
                if (dirs.has(parent)) {
                    isRoot = false;
                    break;
                }
            }
            if (isRoot) {
                tile3DArr.push(item);
            }
        }
        console.timeEnd('FindRoot');
        for (let i = 0; i < tile3DArr.length; i++) {
            const tilePath = tile3DArr[i];
            list.push({
                pid: (0, stringMd5_1.default)(tilePath),
                name: decodeURI(tilePath?.split('/')?.at(-2) || ''),
                catalog: '倾斜三维模型',
                dataType: 'Cesium3DTile',
                showInTree: true,
                showInBox: true,
                defaultLoad: false,
                show: false,
                properties: {
                    maximumScreenSpaceError: 4,
                    url: `${proxyProtocol}://${ip}:${webPort}` + tilePath
                }
            });
        }
        for (const [convertedPath, layerProperties] of dataIndex.tile2D) {
            if (!convertedPath.includes('NaturalEarthII')) {
                list.push({
                    pid: (0, stringMd5_1.default)(convertedPath),
                    name: decodeURI(convertedPath.split('/').at(-4) || ''),
                    catalog: '二维图层瓦片',
                    dataType: 'layer',
                    showInTree: true,
                    showInBox: true,
                    defaultLoad: false,
                    show: false,
                    properties: {
                        url: `${proxyProtocol}://${ip}:${webPort}` + convertedPath,
                        ...layerProperties
                    }
                });
            }
        }
        return list;
    }
};
exports.default = MapResource;
